package com.schoolvisitors.service;

import com.schoolvisitors.entity.*;
import com.schoolvisitors.enums.ReservationStatusEnum;
import com.schoolvisitors.enums.ReservationTypeEnum;
import com.schoolvisitors.exception.BusinessException;
import com.schoolvisitors.repository.*;
import com.schoolvisitors.response.ResultCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.*;
import java.util.*;

@Slf4j
@Service
public class ReservationService {

    private final ReservationRepository reservationRepository;
    private final UserService userService;
    private final SystemConfigService systemConfigService;


    public ReservationService(ReservationRepository reservationRepository, UserService userService, SystemConfigService systemConfigService) {
        this.reservationRepository = reservationRepository;
        this.userService = userService;
        this.systemConfigService = systemConfigService;
    }

    // 判断是否是有效操作时间
//    public boolean isOperationTime(Reservation reservation) {
//        int aheadMinutes = 0;
//        int afterMinutes = 0;
//        LocalDate reservationDate = reservation.getDate();
//        LocalTime startTime = reservation.getTimeSlot().getStartTime();
//        LocalTime endTime = reservation.getTimeSlot().getEndTime();
//
//        if (reservationDate == null || startTime == null || endTime == null) {
//            return false;
//        }
//
//        LocalDateTime now = LocalDateTime.now();
//        LocalDateTime startDateTime = LocalDateTime.of(reservationDate, startTime).minusMinutes(aheadMinutes);
//        LocalDateTime endDateTime = LocalDateTime.of(reservationDate, endTime).plusMinutes(afterMinutes);
//
//        return !now.isBefore(startDateTime) && !now.isAfter(endDateTime);
//    }

    public boolean canCheckIn(Reservation reservation) {
        Long checkBeforeAfterTime = systemConfigService.getSystemConfigToLong("checkBeforeAfterTime");
        int aheadMinutes = Math.toIntExact(checkBeforeAfterTime); // 签到可提前时间
        LocalDate reservationDate = reservation.getDate();
        LocalTime startTime = reservation.getTimeSlot().getStartTime();
        LocalTime endTime = reservation.getTimeSlot().getEndTime();

        if (reservationDate == null || startTime == null || endTime == null) {
            return false;
        }

        LocalDateTime now = LocalDateTime.now();
        LocalDateTime checkInStartTime = LocalDateTime.of(reservationDate, startTime).minusMinutes(aheadMinutes);
        LocalDateTime checkInEndTime = LocalDateTime.of(reservationDate, endTime);

        log.info("当前时间: {}", now);
        log.info("可签到开始时间: {}", checkInStartTime);
        log.info("可签到结束时间: {}", checkInEndTime);

        return !now.isBefore(checkInStartTime) && !now.isAfter(checkInEndTime);
    }

    // 判断是否可以签退（允许延后签退时间）
    public boolean canCheckOut(Reservation reservation) {
        Long checkBeforeAfterTime = systemConfigService.getSystemConfigToLong("checkBeforeAfterTime");
        int afterMinutes = Math.toIntExact(checkBeforeAfterTime);
        LocalDate reservationDate = reservation.getDate();
        LocalTime startTime = reservation.getTimeSlot().getStartTime();
        LocalTime endTime = reservation.getTimeSlot().getEndTime();

        if (reservationDate == null || endTime == null) {
            return false;
        }

        LocalDateTime now = LocalDateTime.now();
        LocalDateTime checkOutStartTime = LocalDateTime.of(reservationDate, startTime); // 签退从预约开始开始
        LocalDateTime checkOutEndTime = LocalDateTime.of(reservationDate, endTime).plusMinutes(afterMinutes);

        // 当前时间在可签退区间内
        return !now.isBefore(checkOutStartTime) && !now.isAfter(checkOutEndTime);
    }


    @Transactional(rollbackFor = Exception.class)
    public void clockInByReservationId(User user, Long reservationId) {
        log.info("{}", reservationId);
        Reservation reservation = reservationRepository.findById(reservationId).orElseThrow(() -> new BusinessException(ResultCode.RESERVATION_NOT_FOUND));

        if (!Objects.equals(reservation.getUser().getId(), user.getId())) {
            throw new BusinessException(ResultCode.NOT_PERMISSION);
        }

        if (reservation.getStatus() != ReservationStatusEnum.APPROVED){
            throw new BusinessException(ResultCode.RESERVATION_IS_REJECTED);
        }
        if (!canCheckIn(reservation)){
            throw new BusinessException(ResultCode.NOT_CHECKED_IN_TIME);
        }
        if (reservation.getCheckInTime() != null) {
            throw new BusinessException(ResultCode.ALREADY_CHECKED_IN);
        }
        reservation.setCheckInTime(LocalDateTime.now());
        reservationRepository.save(reservation);

    }

    @Transactional(rollbackFor = Exception.class)
    public void clockOutByReservationId(User user, Long reservationId) {
        Reservation reservation = reservationRepository.findById(reservationId).orElseThrow(() -> new BusinessException(ResultCode.RESERVATION_NOT_FOUND));
        if (!Objects.equals(reservation.getUser().getId(), user.getId())) {
            throw new BusinessException(ResultCode.NOT_PERMISSION);
        }
        if (reservation.getStatus() != ReservationStatusEnum.APPROVED){
            throw new BusinessException(ResultCode.RESERVATION_IS_REJECTED);
        }
        if (!canCheckOut(reservation)){
            throw new BusinessException(ResultCode.NOT_CHECKED_OUT_TIME);
        }
        if (reservation.getCheckInTime() == null) {
            throw new BusinessException(ResultCode.NOT_CHECKED_IN);
        } else if (reservation.getCheckOutTime() != null) {
            throw new BusinessException(ResultCode.ALREADY_CHECKED_OUT);
        } else {
            reservation.setCheckOutTime(LocalDateTime.now());
            reservationRepository.save(reservation);
        }
    }

    // 预约拒绝审核
    @Transactional
    public void rejectReservation(Long reservationId) {
        Reservation cubicleReservation = reservationRepository.findByIdForLock(reservationId).orElseThrow(() -> new BusinessException(ResultCode.RESERVATION_NOT_FOUND));
        if (cubicleReservation.getStatus() == ReservationStatusEnum.PENDING) {
            cubicleReservation.setStatus(ReservationStatusEnum.REJECTED);
        }
        // 返还积分
        userService.addPoint(cubicleReservation.getUser().getId(), cubicleReservation.getPoints());
        reservationRepository.save(cubicleReservation);
    }

    // 预约通过审核
    public void approveReservation(Long reservationId) {
        Reservation cubicleReservation = reservationRepository.findById(reservationId).orElseThrow(() -> new BusinessException(ResultCode.RESERVATION_NOT_FOUND));
        if (cubicleReservation.getStatus() == ReservationStatusEnum.PENDING) {
            cubicleReservation.setStatus(ReservationStatusEnum.APPROVED);
        }
        reservationRepository.save(cubicleReservation);
    }

    // 获取审核人预约列表
    public Page<Reservation> getReservationsByReviewer(ReservationTypeEnum type, long reviewerId, String search, Pageable pageable) {
        if (search != null) {
            return reservationRepository.searchByTypeAndReviewerAndUserRealName(type, reviewerId, search, pageable);
        }
        return reservationRepository.findByTypeAndReviewerId(type, reviewerId, pageable);
    }

    // 获取审核人未审核的预约记录列表
    public Page<Reservation> getReservationsByReviewerAndNotReview(ReservationTypeEnum type, long reviewerId, Pageable pageable) {
        return reservationRepository.findByTypeAndReviewerIdAndStatus(type, reviewerId, ReservationStatusEnum.PENDING, pageable);
    }


    public Page<Reservation> getNotOutReservationByReviewer(Long reviewerId, String search, Pageable pageable) {
        if (search != null) {
            return reservationRepository.searchByNotOutWarnTrueAndReviewerIdAndUserRealName(reviewerId, search, pageable);
        }
        return reservationRepository.findByNotOutWarnTrueAndReviewerId(reviewerId, pageable);
    }
}
